using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SOM.Model
{
    public class CSVector
    {
        private static readonly Random rand = new Random();
        private static readonly object syncLock = new object();
        private int R_color;
        private int G_color;
        private int B_color;
        private List<double> CSVectorElem;
        private int VectorSize;
        private string seq_filename;
        private double HSV_value;

        public double HSV
        {
            get { return HSV_value; }
            set { HSV_value = value; }
        }

        public string SequenceName
        {
            get { return seq_filename; }
            set { seq_filename = value; }
        }

        struct Simple
        {
            public int position;      //position in csVector
            public double value;      //value of frequency
        };

        public int R
        {
            get { return R_color; }
            set { R_color = value; }
        }

        public int G
        {
            get { return G_color; }
            set { G_color = value; }
        }

        public int B
        {
            get { return B_color; }
            set { B_color = value; }
        }

        public CSVector(int size)
        {
            this.CSVectorElem = new List<double>();
            for (int i = 0; i < size; i++)
            {
                CSVectorElem.Add(0);
            }
            VectorSize = size;
        }

        public CSVector(string file_name, nGrammDictionary Dict, int hamming_dist)
        {
            this.seq_filename = Path.GetFileName(file_name);
            this.CSVectorElem = new List<double>();
            nGrammDictionary tempDict = new nGrammDictionary(Dict);
            DnaParser dnaParser = new DnaParser(file_name);
            for (int index = 0; index <= dnaParser.lengthOfSeq - tempDict.nGramlenght; index++)
            {
                string subString = dnaParser.dna_sequence.Substring(index, tempDict.nGramlenght);


                foreach (var ngram in tempDict.wordDictionary.Keys.ToList())
                {
                    if (HamingDistance(ngram, subString) <= hamming_dist && HamingDistance(ngram, subString) >= 0)
                    {
                        tempDict.wordDictionary[ngram]++;
                    }   //end of if
                }      //end of foreach
            }          //end for 
            foreach (var item in tempDict.wordDictionary)
            {
                CSVectorElem.Add(item.Value);
            }
            VectorSize = CSVectorElem.Count;
        }//end constructor CompositionalSpectrum

        public CSVector()
        {
            this.CSVectorElem = new List<double>();
            VectorSize = CSVectorElem.Count;
            // TODO: Complete member initialization
        }

        public int getVectorSize()
        {
            return VectorSize;
        }

        public List<double> getCSVectorElem()
        {
            return CSVectorElem;
        }

        public double getMax()
        {
            return CSVectorElem.Max();
        }

        public void fillingOnesInVector(int factor)// for inserting values one's into list of vector
        {
            for (int i = 0; i < VectorSize; i++)
            {
                if (i % factor == 0)
                {
                    CSVectorElem[i] = 1;
                }

            }

        }

        public void fillIncreasingValues()
        {
            for (int i = 0; i < VectorSize; i++)
            {
                    CSVectorElem[i] = i;
            }

        }

        public void fill1()
        {
                CSVectorElem[0] = 4;
                CSVectorElem[1] = 3;
                CSVectorElem[2] = 0;
                CSVectorElem[3] = 0;
                CSVectorElem[4] = 2;
                CSVectorElem[5] = 12;
                CSVectorElem[6] = 3;
                CSVectorElem[7] = 2;
                CSVectorElem[8] = 1;
                CSVectorElem[9] = 1;
        }

        public void fill2()
        {
            CSVectorElem[0] = 2;
            CSVectorElem[1] = 7;
            CSVectorElem[2] = 3;
            CSVectorElem[3] = 3;
            CSVectorElem[4] = 0;
            CSVectorElem[5] = 12;
            CSVectorElem[6] = 0;
            CSVectorElem[7] = 3;
            CSVectorElem[8] = 1;
            CSVectorElem[9] = 1;
        }

        public int HamingDistance(string str1, string str2)
        {
            int hamingCount = 0;
            if (str1.Length != str2.Length)
                return -1;
            else
                for (int i = 0; i < str1.Length; i++)
                {
                    if (!str1.Substring(i, 1).Equals(str2.Substring(i, 1)))
                    {
                        hamingCount++;
                    }
                }
            return hamingCount;
        }

        public void InitRandom(int size, int max_range)
        {
           
            for (int i = 0; i < size; i++)
            {

                lock (syncLock)
                { // synchronize
                    CSVectorElem.Add(rand.Next(max_range));
                }
               
            }
            VectorSize = CSVectorElem.Count;

        }

        //calculation Spearman's rank correlation coefficient
        public double Coorelation(CSVector Vector)
        {
            return vecSubtraction(this, Vector).getCsVectorSizeNormal();
        }

        public List<double> Rank()
        {
            bool flag = true;
            Simple temp;
            int index = 1;
            double temp_seq;

            List<Simple> PosVect = new List<Simple>();
            foreach (var item in this.CSVectorElem)
            {
                temp.position = index++;
                temp.value = item;
                PosVect.Add(temp);
            }

            for (int i = 0; i < PosVect.Count-1 && flag; i++)
            {
                flag = false;
                for (int j = i+1; j < PosVect.Count; j++)
                {
                    if (PosVect[i].value > PosVect[j].value)
                    {
                        temp = PosVect[i];
                        PosVect[i] = PosVect[j];
                        PosVect[j] = temp;
                        flag = true;
                    }

                }
            }

            List<double> rankVec = new List<double>(this.VectorSize);
            for (int i = 0; i < rankVec.Capacity; i++)
            {
                rankVec.Add(0.0);
            }


            int count=0;
            int low_index=1;
            int upper_index=1;
            int k = 1;
            double order_index_sum= 0;
            temp_seq=PosVect[0].value;
            List<int> count_freq = new List<int>();

           

            for (int i = 1; i <= PosVect.Count; i++)
            { 
                
                
                if(temp_seq!=PosVect[i-1].value)
                {
                                      
                   
                    
                    for ( k = low_index-1; k < upper_index-1; k++)
                    {
                        rankVec[PosVect[k].position - 1] =(double) order_index_sum/(double)count;
                    
                    }
                    low_index = upper_index;
                    order_index_sum = i;                    
                    count = 1;
                    temp_seq = PosVect[i - 1].value;
                }
                else
                {
                    order_index_sum+=i;
                    upper_index++;
                    count++;
                }
                
            }

            for (k = low_index - 1; k < upper_index ; k++)
            {
                rankVec[PosVect[k].position - 1] = (double)order_index_sum / (double)count;

            }
           return rankVec;

        }

        //public List<int> Rank_old()
        //{
        //    Simple temp;
        //    int maxRangeFreq; //Maximum value range of frequencies
        //    int index = 1;

        //    List<Simple> PosVect = new List<Simple>();
        //    foreach (var item in this.CSVectorElem)
        //    {
        //        temp.position = index++;
        //        temp.value = item;
        //        PosVect.Add(temp);
        //    }
        //    maxRangeFreq = this.CSVectorElem.Max();
        //    List<List<Simple>> rangVect = new List<List<Simple>>(maxRangeFreq + 1);
        //    for (int i = 0; i < rangVect.Capacity; i++)
        //    {
        //        rangVect.Add(new List<Simple>());
        //    }

        //    foreach (var item in PosVect)
        //    {
        //        rangVect[item.value].Add(item);
        //    }
        //    List<int> rankVec = new List<int>(this.VectorSize);
        //    for (int i = 0; i < rankVec.Capacity; i++)
        //    {
        //        rankVec.Add(0);
        //    }
        //    int ordInd = 1;                     //  compiting index
        //    foreach (var freqVec in rangVect)  //Note: List<Simple> freqVec
        //    {
        //        foreach (var item in freqVec)  //Note: Simple item
        //        {
        //            rankVec[item.position - 1] = ordInd++;//ordInd
        //        }
        //    }
        //    return rankVec;
        //}

        public double getCsVectorSizeNormal()
        {
            double sum  = 0;
            foreach (var item in CSVectorElem)
            {
                sum += Math.Pow(item, 2);       
        
            }

            return Math.Sqrt(sum);
        
        }

        internal void updateWeight(double theta, CSVector bmuCsVector)
        {
            for (int i = 0; i < this.VectorSize; i++)
            {
                //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
                CSVectorElem[i] += (theta * (bmuCsVector.CSVectorElem[i] - CSVectorElem[i]));
            }

        }

        internal CSVector vecSubtraction(CSVector vec1, CSVector vec2)
        {
            CSVector substrVect = new CSVector();
            for (var item = 0; item < vec1.CSVectorElem.Count; item++)
            {
                substrVect.CSVectorElem.Add(vec1.CSVectorElem[item] - vec2.CSVectorElem[item]);
            }
            return substrVect;

        }
    }
}
